#ifndef _WX_DYNLIB_H__
#define _WX_DYNLIB_H__

#include "wx/defs.h"

#if wxUSE_DYNLIB_CLASS

#include "wx/string.h"
#include "wx/dynarray.h"

#if defined(__OS2__) || defined(__EMX__)
#include "wx/os2/private.h"
#endif

#if (defined(HAVE_DLERROR) && !defined(__EMX__)) || defined(__DARWIN__)
#define wxHAVE_DYNLIB_ERROR
#endif

class wxDynamicLibraryDetailsCreator;

#if defined(__OS2__) || defined(__EMX__) || defined(__WINDOWS__)
typedef HMODULE             wxDllType;
#elif defined(__DARWIN__)
typedef void               *wxDllType;
#elif defined(HAVE_DLOPEN)
#include <dlfcn.h>
typedef void               *wxDllType;
#elif defined(HAVE_SHL_LOAD)
#include <dl.h>
typedef shl_t               wxDllType;
#elif defined(__WXMAC__)
#include <CodeFragments.h>
typedef CFragConnectionID   wxDllType;
#else
#error "Dynamic Loading classes can't be compiled on this platform, sorry."
#endif

enum wxDLFlags {
  wxDL_LAZY       = 0x00000001,   // resolve undefined symbols at first use
  wxDL_NOW        = 0x00000002,   // resolve undefined symbols on load
  wxDL_GLOBAL     = 0x00000004,   // export extern symbols to subsequently
  wxDL_VERBATIM   = 0x00000008,   // attempt to load the supplied library
  wxDL_NOSHARE    = 0x00000010,   // load new DLL, don't reuse already loaded
  wxDL_QUIET      = 0x00000020,   // don't log an error if failed to load

  wxDL_GET_LOADED = 0x00000040,   // Win32 only: return handle of already

  wxDL_DEFAULT    = wxDL_NOW      // default flags correspond to Win32
};

enum wxDynamicLibraryCategory {
  wxDL_LIBRARY,       // standard library
  wxDL_MODULE         // loadable module/plugin
};

enum wxPluginCategory {
  wxDL_PLUGIN_GUI,    // plugin that uses GUI classes
  wxDL_PLUGIN_BASE    // wxBase-only plugin
};

#define wxDYNLIB_FUNCTION(type, name, dynlib) \
  type pfn ## name = (type)(dynlib).GetSymbol(wxT(#name))

class wxDynamicLibraryDetails {
  public:
    wxDynamicLibraryDetails() { m_address = NULL; m_length = 0; }
    wxString GetName() const { return m_name; }
    wxString GetPath() const { return m_path; }
    bool GetAddress( void **addr, size_t *len ) const {
      if( !m_address ) {
        return false;
      }
      if( addr ) {
        *addr = m_address;
      }
      if( len ) {
        *len = m_length;
      }
      return true;
    }
    wxString GetVersion() const {
      return m_version;
    }
  private:
    wxString m_name, m_path, m_version;
    void *m_address;
    size_t m_length;
    friend class wxDynamicLibraryDetailsCreator;
};

WX_DECLARE_USER_EXPORTED_OBJARRAY( wxDynamicLibraryDetails,wxDynamicLibraryDetailsArray);

class wxDynamicLibrary {
  public:
    static wxDllType         GetProgramHandle();
    static const wxChar *GetDllExt() { return ms_dllext; }
    wxDynamicLibrary() : m_handle( 0 ) { }
    wxDynamicLibrary( const wxString& libname, int flags = wxDL_DEFAULT )
      : m_handle( 0 ) {
      Load( libname, flags );
    }
    ~wxDynamicLibrary() { Unload(); }
    bool IsLoaded() const { return m_handle != 0; }
    bool Load( const wxString& libname, int flags = wxDL_DEFAULT );
    static wxDllType RawLoad( const wxString& libname, int flags = wxDL_DEFAULT );
    wxDllType Detach() { wxDllType h = m_handle; m_handle = 0; return h; }
    static void Unload( wxDllType handle );
    void Unload() { if( IsLoaded() ) { Unload( m_handle ); m_handle = 0; } }
    wxDllType GetLibHandle() const { return m_handle; }
    bool HasSymbol( const wxString& name ) const {
      bool ok;
      DoGetSymbol( name, &ok );
      return ok;
    }

    void *GetSymbol( const wxString& name, bool *success = NULL ) const;

    static void *RawGetSymbol( wxDllType handle, const wxString& name );
    void *RawGetSymbol( const wxString& name ) const {
      #if defined (__WXPM__) || defined(__EMX__)
      return GetSymbol( name );
      #else
      return RawGetSymbol( m_handle, name );
      #endif
    }

    static wxDynamicLibraryDetailsArray ListLoaded();
    static wxString CanonicalizeName( const wxString& name, wxDynamicLibraryCategory cat = wxDL_LIBRARY );
    static wxString
    CanonicalizePluginName( const wxString& name, wxPluginCategory cat = wxDL_PLUGIN_GUI );
    static wxString GetPluginsDirectory();
  protected:
    void *DoGetSymbol( const wxString& name, bool *success = 0 ) const;

    #ifdef wxHAVE_DYNLIB_ERROR
    static void Error();
    #endif
    static const wxChar *ms_dllext;
    wxDllType m_handle;
    DECLARE_NO_COPY_CLASS( wxDynamicLibrary )
};

#define WXDLL_ENTRY_FUNCTION() \
  extern "C" WXEXPORT const wxClassInfo *wxGetClassFirst(); \
  const wxClassInfo *wxGetClassFirst() { \
    return wxClassInfo::GetFirst(); \
  }

#endif

#endif
